import { GameConfig } from "../configs/GameConfig";
import GameModel from "../model/GameModel";
import RobotModel from "../model/RobotModel";
import { BoutModuleS, EnumBoutState } from "../modules/BoutModule";
import { StateBase } from "./StateMachine";
import { DamageInformation, UnitStage } from "./UnitStage";
import { util } from "./Util";

export class FightingCharacter {
    constructor(public sceneID: number, public character: Character, public robotData?: RobotModel) { }
}

export class BoutState extends StateBase<EnumBoutState> {
    protected boutMD: BoutModuleS;
    protected stateEnterTimestamp = 0;
    protected exitTimeSecond = -1;

    constructor() {
        super(true);
        this.boutMD = ModuleService.getModule(BoutModuleS);
    }

    onEnter(): void {
        this.stateEnterTimestamp = Date.now();
        console.log(`->${this.constructor.name}`);
        GameModel.instance.boutState = this.id
        
    }

    onLogicUpdate(): void {
        let now = Date.now();
        if (this.exitTimeSecond != -1 && (this.stateEnterTimestamp + this.exitTimeSecond * 1000) < now) {
            this.fsm.canExitCurrent();
        }
    }

    onPlayerExitGame(playerID: number) { }

    protected setExitTime(second: number) {
        this.exitTimeSecond = second;
    }
}

export class LeisureState extends BoutState {
    constructor() {
        super();
        this.setExitTime(5);
    }
}

export class PrepareState extends BoutState {
    constructor() {
        super();
        this.setExitTime(10);
    }

    onEnter(): void {
        super.onEnter();
    }

    onLogicUpdate(): void {
        super.onLogicUpdate()
        let now = Date.now();
        let leftSecond = ((this.stateEnterTimestamp + this.exitTimeSecond * 1000) - now) * 0.001
        GameModel.instance.fightingBeginTime = leftSecond
    }
}

export class FightState extends BoutState {
    // 圈变更事件
    onCircleChanged:Action = new Action()
    // 战斗信息
    get CircleCenter(): Vector { return this.currentCircleCenter }
    get CircleRadius(): number { return this.currentCircleRadius }
    get FightingCharacters(): FightingCharacter[] { return this.fightingCharacterArray }
    // 变圈时间
    private readonly circleChangeSecond = 15
    // 圈最大最小值
    private readonly circleRadiusMax = 800
    private readonly circleRadiusMin = 250
    // 变圈范围
    private readonly circleRangeA = new Vector(1850, 1900, 0)
    private readonly circleRangeB = new Vector(-1850, -1900, 0)
    // 最大圈到最小圈经历几次
    private readonly circleLessenTimes = 8
    // 单局最少多少人
    private readonly fightingCharacterCount = GameConfig.Robot.getAllElement().length

    private circleChangeInterval = 0
    private currentCircleCenter = Vector.zero
    private currentCircleRadius = 0
    private currentCircleChangeCount = 0
    private robotModelPool: RobotModel[] = []
    private fightingCharacterArray: FightingCharacter[] = [];

    constructor() {
        super();
        for (const cfg of GameConfig.Robot.getAllElement()) {
            let character = <Character>GameObject.findGameObjectById(cfg.RobotGuid)
            let model = character.addComponent(RobotModel)
            model.init(cfg, this)
            this.robotModelPool.push(model)
        }
    }

    onEnter(): void {
        super.onEnter();
        this.circleChangeInterval = 0
        this.currentCircleChangeCount = 0
        // 重置圈
        this.lessenCircle()
        // 填充注册加入游戏的玩家
        for (const sighupPlayerID of this.boutMD.signupPlayerArray) {
            let player = Player.getPlayer(sighupPlayerID);
            let fightCharacter = new FightingCharacter(sighupPlayerID, player.character);
            this.fightingCharacterArray.push(fightCharacter);
            GameModel.instance.fightingCharacter.push(sighupPlayerID);
        }
        // 填充机器人
        for (let i = this.fightingCharacterArray.length; i < this.fightingCharacterCount; i++) {
            let robotModel = this.robotModelPool[i];
            let fightCharacter = new FightingCharacter(robotModel.sceneID, robotModel.character, robotModel);
            robotModel.enable();
            this.fightingCharacterArray.push(fightCharacter);
            GameModel.instance.fightingCharacter.push(robotModel.sceneID);
            robotModel.fsm.onInit()
            // 注册可被攻击回调
            UnitStage.addUnitToStage({
                sceneID:robotModel.sceneID,
                attackableGameObject:robotModel.character,
                hitCallback:this.robotBeHitCallback,
                caller:this,
            })
        }
        // 传送玩家到比赛场地
        for (let i = 0; i < this.fightingCharacterArray.length; i++) {
            let fightCharacter = this.fightingCharacterArray[i];
            let circlePosition = util.getCirclePosition(800, this.fightingCharacterArray.length, i);
            circlePosition.add(new Vector(0, 0, 500))
            fightCharacter.character.worldTransform.position = circlePosition;
        }
    }

    onUpdate(dt: number): void {
        this.circleChangeChecker(dt)
        this.robotUpdate(dt)
    }
    
    onLogicUpdate(): void { 
        this.robotLogicUpdate()
    }

    onExit():void{
        for (const character of this.fightingCharacterArray) {
            this.removeFightingCharacter(character.sceneID)
        }
    }

    onPlayerExitGame(playerID:number){
        this.removeFightingCharacter(playerID)
    }

    // 缩圈倒计时
    private circleChangeChecker(dt: number) {
        this.circleChangeInterval += dt
        GameModel.instance.nextLessenCircleTime = this.circleChangeSecond - this.circleChangeInterval
        if (this.circleChangeInterval <= this.circleChangeSecond) return
        this.circleChangeInterval = 0
        // 检测当前圈是否有玩家出局
        this.defeatedChecker()
        // 重置新圈
        this.lessenCircle()
    }

    // 变更生存圈
    private lessenCircle() {
        // 变圈
        this.currentCircleCenter = new Vector(
            util.lerp(this.circleRangeA.x, this.circleRangeB.x, Math.random()),
            util.lerp(this.circleRangeA.y, this.circleRangeB.y, Math.random()),
            util.lerp(this.circleRangeA.z, this.circleRangeB.z, 0.5),
        )
        // 缩圈
        this.currentCircleRadius = util.lerp(this.circleRadiusMax, this.circleRadiusMin, Math.min(1, this.currentCircleChangeCount / this.circleLessenTimes))
        // 记录缩圈次数
        this.currentCircleChangeCount++
        // 派发给客户端
        this.boutMD.syncCircleRange(this.currentCircleCenter, this.currentCircleRadius)
        // 派发事件
        this.onCircleChanged.call()
    }

    // 死亡检测
    private defeatedChecker() {
        for (const fightCharacter of this.fightingCharacterArray) {
            let playerPos = fightCharacter.character.worldTransform.position
            let dis = Vector.distance(playerPos, this.currentCircleCenter)
            if (dis < this.currentCircleRadius) continue
            // 通知前端
            this.boutMD.syncCharacterBeDefeated(fightCharacter.sceneID)
            // 移除角色
            this.removeFightingCharacter(fightCharacter.sceneID)
        }
        // 对局正常进行
        if(this.fightingCharacterArray.length > 1) return
        // 获胜者产生
        if(this.fightingCharacterArray.length == 1){
            this.boutMD.syncWinner(this.fightingCharacterArray[0].sceneID)
        }
        // 一轮筛选后所有玩家都死了
        else if (this.fightingCharacterArray.length == 0){
            this.boutMD.syncNoWinner()
        }
        // 退出当前对局
        this.fsm.canExitCurrent()
    }

    // 机器人移动
    private robotUpdate(dt: number) {
        for (const robot of this.fightingCharacterArray) {
            if(!RobotModel.isRobot(robot.sceneID)) continue
            robot.robotData.fsm.onUpdate(dt)
        }
    }

    // 机器人逻辑帧更新
    private robotLogicUpdate() {
        for (const robot of this.fightingCharacterArray) {
            if(!RobotModel.isRobot(robot.sceneID)) continue
            robot.robotData.fsm.onLogicUpdate()
        }
    }

    // 机器人被攻击回调
    private robotBeHitCallback(message:DamageInformation){
        let targetCharacter = GameModel.instance.getCharacterBySceneID(message.targetSceneID)
        let formCharacter = GameModel.instance.getCharacterBySceneID(message.fromSceneID)
        
        if (!targetCharacter || !formCharacter) return
        let dir = Vector.subtract(targetCharacter.worldTransform.position, formCharacter.worldTransform.position).normalized
        dir.z = 0.8
        targetCharacter.addImpulse(targetCharacter.velocity.multiply(-1))
        targetCharacter.addImpulse(dir.multiply(1200), true)
        EffectService.playAtPosition('151580', targetCharacter.worldTransform.position, { scale: new Vector(2, 2, 2) })
    }

    // 从对局中删除角色
    private removeFightingCharacter(sceneID:number){
        if(RobotModel.isRobot(sceneID)){
            UnitStage.removeUnitFromStage(sceneID)
        }
        // 玩家被移回平台
        if(RobotModel.isRobot(sceneID)){
            let robot = RobotModel.robotMap.get(sceneID)
            robot?.disable()
        }else{
            let playerCharacter = GameModel.instance.getCharacterBySceneID(sceneID)
            if(playerCharacter){
                playerCharacter.worldTransform.position = GameModel.instance.playerStartPosition
            }
        }
        // 消除对局人员
        this.fightingCharacterArray = this.fightingCharacterArray.filter(c => c.sceneID != sceneID)
        GameModel.instance.fightingCharacter = GameModel.instance.fightingCharacter.filter(id => id != sceneID)
    }
}
